﻿using System.Data.Entity.Infrastructure;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Vowei.Core.Models;
using Vowei.Data;
using System.Linq;
using Vowei.Data.Models;
using Vowei.Core;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.IO;
using Vowei.Data.Helpers;

namespace vowei.test
{    
    /// <summary>
    ///这是 VoweiContextTest 的测试类，旨在
    ///包含所有 VoweiContextTest 单元测试
    ///</summary>
    [TestClass()]
    public class VoweiContextTest : TestBase
    {
        [TestMethod()]
        public void VoweiContextConstructorTest()
        {
            VoweiContextImpl target = new VoweiContextImpl();
            Assert.IsNotNull(target);
        }

        [TestMethod]
        public void AddSingleItemSaveChangesTest()
        {
            using (var impl = new VoweiContextImpl())
            {
                // 先创建一个新的项目
                var project = new Project()
                {
                    Title = "AddMilestoneTest_Project",
                    Owner = Constants.BuiltIn.Users.Administrator,
                    StartDate = DateTime.Now
                };
                impl.Projects.Add(project);
                impl.SaveChanges();
            }
        }

        [TestMethod]
        public void CreateRequirementAndChildTicketSaveChangesTest()
        {
            using (var impl = new VoweiContextImpl())
            {
                var project = new Project()
                {
                    Title = "CreateRequirementAndChildTicketSaveChangesTest_Project",
                    Owner = Constants.BuiltIn.Users.Administrator
                };
                impl.Projects.Add(project);
                impl.SaveChanges();
                
                var requirement = new Requirement()
                {
                    Title = "CreateRequirementAndChildTicketSaveChangesTest_Requirement",
                    AssignedTo = Constants.BuiltIn.Users.Administrator,
                    BelongsToMilestone = project
                };

                var titles = new string[] {
                    "CreateRequirementAndChildTicketSaveChangesTest_Task1",
                    "CreateRequirementAndChildTicketSaveChangesTest_Task2",
                    "CreateRequirementAndChildTicketSaveChangesTest_Task3",
                    "CreateRequirementAndChildTicketSaveChangesTest_Task4"
                };

                foreach (var title in titles)
                {
                    var item = impl.Create<Task>(title);
                    item.AssignedTo = Constants.BuiltIn.Users.Administrator;

                    requirement.Children.Add(item);
                }

                titles = new string[]
                {
                    "CreateRequirementAndChildTicketSaveChangesTest_Requirement1",
                    "CreateRequirementAndChildTicketSaveChangesTest_Requirement2",
                    "CreateRequirementAndChildTicketSaveChangesTest_Requirement3",
                    "CreateRequirementAndChildTicketSaveChangesTest_Requirement4"
                };

                foreach (var title in titles)
                {
                    var item = impl.Create<Requirement>(title);
                    item.AssignedTo = Constants.BuiltIn.Users.Administrator;
                    item.BelongsToMilestone = project;

                    requirement.Children.Add(item);
                }
                impl.Requirements.Add(requirement);

                impl.SaveChanges();
            }
        }

        [TestMethod]
        public void CreateProjectAndChildMilestoneSaveChangesTest()
        {
            using (var impl = new VoweiContextImpl())
            {
                var project = new Project()
                {
                    Title = "CMMI 项目",
                    Owner = Constants.BuiltIn.Users.Administrator
                };
                impl.Projects.Add(project);

                var titles = new string[] 
                {
                    "Performed Process",
                    "Managed Process",
                    "Defined Process",
                    "Quantitative Managed Process",
                    "Optimizing Process"
                };
                var id = Guid.Empty;
                foreach (var title in titles)
                {
                    var item = impl.Create<Milestone>(title);
                    if (id.CompareTo(Guid.Empty) == 0)
                        id = item.ID;
                    project.Children.Add(item);
                    impl.Milestones.Add(item);
                }
                impl.SaveChanges();

                var milestone = impl.Milestones.Find(id);

                titles = new string[] 
                {
                    "Establish an Organizational Policy",
                    "Plan the Process",
                    "Provide Resources",
                    "Assign Responsibility",
                    "Train People",
                    "Manage Configuration",
                    "Identify and Involve Relevant Stackholders",
                    "Monitor and Control the Process",
                    "Objectively Evaluate Adherence",
                    "Review Status with Higher Level Management"
                };

                foreach (var title in titles)
                {
                    var item = impl.Create<Requirement>(title);
                    item.AssignedTo = Constants.BuiltIn.Users.Administrator;
                    item.BelongsToMilestone = milestone;

                    impl.Requirements.Add(item);
                }

                impl.SaveChanges();
            }
        }

        [TestMethod]
        public void RemoveMilestoneTest()
        {
            var project = TestBase.CreateProjectHelper("RemoveMilestoneTest");
            var milestone = TestBase.CreateMilestoneHelper("RemoveMilestoneTest");
            project.Children.Add(milestone);

            var requirement = TestBase.CreateRequirementHelper("RemoveMilestoneTest", milestone);
            var task = TestBase.CreateTaskHelper("RemoveMilestoneTest", project);
            requirement.Children.Add(task);

            using (var impl = new VoweiContextImpl())
            {
                var context = new VoweiContext(impl);
                impl.Projects.Add(project);
                impl.Milestones.Add(milestone);
                impl.Tasks.Add(task);
                impl.Requirements.Add(requirement);
                impl.SaveChanges();

                var tasks = project.AllTasks(context);
                Assert.AreEqual(1, tasks.Count());
            }

            using (var impl = new VoweiContextImpl())
            {
                var context = new VoweiContext(impl);
                milestone = impl.Milestones.Include("BelongsToMilestone").Single(m => m.ID == milestone.ID);

                foreach (var r in impl.Requirements.Where(r1 => r1.BelongsToMilestone.ID == milestone.ID))
                    r.BelongsToMilestone = milestone.BelongsToMilestone;

                impl.Milestones.Remove(milestone);
                impl.SaveChanges();

                requirement = impl.Requirements.Find(requirement.ID);
                var tasks = project.AllTasks(context);

                Assert.AreEqual(1, requirement.Children.Count());
                Assert.IsTrue(task.ID.CompareTo(requirement.Children.ElementAt(0).ID) == 0);
                Assert.AreEqual(1, tasks.Count());
                Assert.IsTrue(task.ID.CompareTo(tasks.First().ID) == 0);
            }
        }

        [TestMethod]
        public void RemoveMilestoneNeedExplictChangeMilestoneTest()
        {
            var project = TestBase.CreateProjectHelper("RemoveMilestoneNeedExplictChangeMilestoneTest");
            var milestone = TestBase.CreateMilestoneHelper("RemoveMilestoneNeedExplictChangeMilestoneTest");
            project.Children.Add(milestone);

            var requirement = TestBase.CreateRequirementHelper("RemoveMilestoneNeedExplictChangeMilestoneTest", milestone);
            var task = TestBase.CreateTaskHelper("RemoveMilestoneNeedExplictChangeMilestoneTest", project);
            requirement.Children.Add(task);

            using (var impl = new VoweiContextImpl())
            {
                var context = new VoweiContext(impl);
                impl.Projects.Add(project);
                impl.Milestones.Add(milestone);
                impl.Tasks.Add(task);
                impl.Requirements.Add(requirement);
                impl.SaveChanges();

                var tasks = project.AllTasks(context);
                Assert.AreEqual(1, tasks.Count());
            }

            using (var impl = new VoweiContextImpl())
            {
                var context = new VoweiContext(impl);
                milestone = impl.Milestones.Find(milestone.ID);
                project = impl.Projects.Find(project.ID);

                // 需要明确指定删除了里程碑以后，相关的需求的放置问题
                foreach (var r in impl.Requirements.Where(r1 => r1.BelongsToMilestone.ID == milestone.ID))
                    r.BelongsToMilestone = project;

                impl.Milestones.Remove(milestone);
                impl.SaveChanges();

                requirement = impl.Requirements.Find(requirement.ID);
                requirement.BelongsToMilestone = project;
                impl.SaveChanges();

                requirement = impl.Requirements.Find(requirement.ID);
                var tasks = project.AllTasks(context);
                Assert.AreEqual(1, tasks.Count());
                Assert.IsTrue(task.ID.CompareTo(tasks.First().ID) == 0);
                Assert.IsTrue(project.ID.CompareTo(requirement.BelongsToMilestone.ID) == 0);
            }
        }

        [TestMethod]
        public void ModifyMilestoneParentTest()
        {
            var project = TestBase.CreateProjectHelper("ModifyMilestoneParentTest");
            var milestone = TestBase.CreateMilestoneHelper("ModifyMilestoneParentTest");

            project.Children.Add(milestone);
            using (var impl = new VoweiContextImpl())
            {
                impl.Milestones.Add(milestone);
                impl.Projects.Add(project);
                impl.SaveChanges();
            }

            var parentMilestone = TestBase.CreateMilestoneHelper("ModifyMilestoneParentTest_Parent");
            
            using (var impl = new VoweiContextImpl())
            {
                impl.QuerableContext.AttachTo("Milestones", milestone);
                project.Children.Remove(milestone);
                impl.SaveChanges();

                project.Children.Add(parentMilestone);
                parentMilestone.Children.Add(milestone);
                impl.Milestones.Add(parentMilestone);
                impl.SaveChanges();
            }
        }

        [TestMethod]
        public void ProjectMilestoneChildBasicTest()
        {
            var project = TestBase.CreateProjectHelper("ProjectMilestoneChildBasicTest");
            var milestone = TestBase.CreateMilestoneHelper("ProjectMilestoneChildBasicTest");

            using (var impl = new VoweiContextImpl())
            {
                project.Children.Add(milestone);
                impl.Milestones.Add(milestone);
                impl.Projects.Add(project);

                impl.SaveChanges();

                var actual = impl.Projects.Find(project.ID);
                Assert.AreEqual(1, actual.Children.Count);
                Assert.AreEqual(milestone.ID, actual.Children.ElementAt(0).ID);
            }
        }

        [TestMethod]
        public void ProjectMilestoneChildChangeBasicTest()
        {
            var project = TestBase.CreateProjectHelper("ProjectMilestoneChildBasicTest");
            var milestone = TestBase.CreateMilestoneHelper("ProjectMilestoneChildBasicTest");

            using (var impl = new VoweiContextImpl())
            {
                project.Children.Add(milestone);
                impl.Projects.Add(project);

                impl.SaveChanges();

                project.Children.Remove(milestone);
                impl.SaveChanges();

                var actual = impl.Projects.Find(project.ID);
                Assert.AreEqual(0, actual.Children.Count);
                Assert.IsTrue(impl.Milestones.Any(m => m.ID == milestone.ID));

                project.Children.Add(milestone);
                impl.SaveChanges();

                Assert.AreEqual(1, actual.Children.Count);
                Assert.AreEqual(milestone.ID, actual.Children.ElementAt(0).ID);
                Assert.IsTrue(impl.Milestones.Any(m => m.ID == milestone.ID));

                impl.Milestones.Remove(milestone);
                impl.SaveChanges();

                Assert.AreEqual(0, actual.Children.Count);
            }
        }

        [TestMethod]
        public void ProjectEmployeeForeignKeyTest()
        {
            var project = TestBase.CreateProjectHelper("ProjectEmployeeForeignKeyTest");
            var employee = new Employee()
            {
                Email = "ProjectEmployeeForeignKeyTest@vowei.com",
                Company = "Vowei",
                Department = "Development"
            };

            using (var impl = new VoweiContextImpl())
            {
                project.ResourceAssignments.Add(new ResourceAssignment()
                {
                    ResourceId = employee.ID,
                    ProjectId = project.ID,
                    WorkCalendarId = project.ProjectBaseCalendarId
                });
                impl.Projects.Add(project);
                impl.SaveChanges();
            }

            using (var impl = new VoweiContextImpl())
            {
                var actual = impl.Projects.Include("ResourceAssignments").Single(p => p.ID == project.ID);
                Assert.AreNotEqual(0, actual.ResourceAssignments.Count());

                var actualEmployee = actual.ResourceAssignments[0];
                // actualEmployee = impl.Assignments.First(a => a.ResourceId == actualEmployee.ID);
                Assert.AreEqual(project.ID, actualEmployee.ProjectId);
                Assert.AreEqual(employee.ID, actualEmployee.ResourceId);
            }
        }

        [TestMethod]
        public void ScmForeignKeyTest()
        {
            var project = TestBase.CreateProjectHelper("ScmForeignKeyTest");
            var change = new ChangeSet()
            {
                Title = "2",
                Project = project,
                ChangedFileList = "changedtestfile.cs"
            };

            using (var impl = new VoweiContextImpl())
            {
                impl.Projects.Add(project);
                impl.SaveChanges();

                impl.ChangeSet.Add(change);
                impl.SaveChanges();
            }

            using (var impl = new VoweiContextImpl())
            {
                var actual = impl.ChangeSet.Include("Project").Single(c => c.ID == change.ID);

                Assert.IsNotNull(actual.Project);
                Assert.AreEqual(project.ID, actual.Project.ID);
                Assert.AreEqual(change.Title, actual.Title);
            }
        }

        [TestMethod]
        public void TicketBelongsToMilestoneForeignKeyTest()
        {
            var project = TestBase.CreateProjectHelper("TicketBelongsToMilestoneForeignKeyTest");
            var milestone = TestBase.CreateMilestoneHelper("TicketBelongsToMilestoneForeignKeyTest");
            var requirement = TestBase.CreateRequirementHelper("TicketBelongsToMilestoneForeignKeyTest", project);

            using (var impl = new VoweiContextImpl())
            {
                var context = new VoweiContext(impl);
                context.Requirements.Add(requirement);
                context.SaveChanges();
            }

            using (var impl = new VoweiContextImpl())
            {
                var context = new VoweiContext(impl);
                var actual = (Requirement)context.Requirements.Include("BelongsToMilestone").Query.Single(r => r.ID == requirement.ID);
                Assert.IsNotNull(actual);
                Assert.IsNotNull(actual.BelongsToMilestone);
                Assert.AreEqual(project.ID, actual.BelongsToMilestoneId);
                Assert.AreEqual(project.ID, actual.BelongsToMilestone.ID);
            }

            requirement = TestBase.CreateRequirementHelper("TicketBelongsToMilestoneForeignKeyTest_Another", milestone);
            using (var impl = new VoweiContextImpl())
            {
                var context = new VoweiContext(impl);
                context.Requirements.Add(requirement);
                context.SaveChanges();
            }

            using (var impl = new VoweiContextImpl())
            {
                var context = new VoweiContext(impl);
                var actual = (Requirement)context.Requirements.Include("BelongsToMilestone").Query.Single(r => r.ID == requirement.ID);
                Assert.IsNotNull(actual);
                Assert.IsNotNull(actual.BelongsToMilestone);
                Assert.AreEqual(milestone.ID, actual.BelongsToMilestoneId);
                Assert.AreEqual(milestone.ID, actual.BelongsToMilestone.ID);
            }
        }

        [TestMethod]
        public void MilestoneBelongsToMilestoneForeignKeyTest()
        {
            var project = TestBase.CreateProjectHelper("MilestoneBelongsToMilestoneForeignKeyTest");
            var milestone = TestBase.CreateMilestoneHelper("MilestoneBelongsToMilestoneForeignKeyTest");
            milestone.BelongsToMilestone = project;

            using (var impl = new VoweiContextImpl())
            {
                var context = new VoweiContext(impl);
                context.Milestones.Add(milestone);
                context.SaveChanges();
            }

            using (var impl = new VoweiContextImpl())
            {
                var context = new VoweiContext(impl);
                var actual = context.Milestones.Include("BelongsToMilestone").Query.First(m => m.ID == milestone.ID);
                Assert.AreEqual(project.ID, actual.BelongsToMilestoneId);
                Assert.IsNotNull(actual.BelongsToMilestone);
                Assert.IsNotNull(actual.GetBelongingProject(context));
                Assert.AreEqual(project.ID, actual.BelongsToMilestone.ID);
                Assert.AreEqual(project.ID, actual.GetBelongingProject(context).ID);
            }
        }

        [TestMethod]
        public void AddEmployeeTest()
        {
            var manager = new Employee()
            {
                Company = "Vowei",
                Department = "Development",
                DisplayName = "Shi Yimin",
                Email = "yimin@vowei.com",
                Level = "SDE I",
                OnboardDate = DateTime.Now,
                Title = "SDE",
                UserName = "vowei\\yimin"
            };

            using (var impl = new VoweiContextImpl())
            {
                var context = new VoweiContext(impl);
                if (context.Employees.Find(manager.Email) == null)
                    context.Employees.Add(manager);

                context.SaveChanges();
            }

            using (var impl = new VoweiContextImpl())
            {
                var context = new VoweiContext(impl);
                var actual = context.Employees.Find(manager.Email);

                Assert.IsNotNull(actual);
                Assert.AreEqual(manager.Company, actual.Company);
                Assert.AreEqual(manager.DisplayName, actual.DisplayName);
                Assert.AreEqual(manager.UserName, actual.UserName);
            }

            var employee = new Employee()
            {
                Company = "Vowei",
                Department = "Development",
                DisplayName = "Employee",
                Email = "employee@vowei.com",
                Level = "SDE I",
                OnboardDate = DateTime.Now,
                Title = "SDE",
                UserName = "vowei\\employee"
            };

            using (var impl = new VoweiContextImpl())
            {
                var context = new VoweiContext(impl);
                var item = context.Employees.Find(employee.Email);
                if (item != null)
                    context.Employees.Remove(item);
                context.SaveChanges();

                employee.ReportTo = context.Employees.Find(manager.Email);

                context.Employees.Add(employee);
                context.SaveChanges();
            }

            using (var impl = new VoweiContextImpl())
            {
                var context = new VoweiContext(impl);
                var actual = context.Employees.Include("ReportTo").Query.First(e => e.Email == employee.Email);

                Assert.IsNotNull(actual);
                Assert.AreEqual(employee.Company, actual.Company);
                Assert.AreEqual(employee.DisplayName, actual.DisplayName);
                Assert.AreEqual(employee.UserName, actual.UserName);
                Assert.IsNotNull(actual.ReportTo);
                Assert.AreEqual(employee.ReportTo.Email, actual.ReportTo.Email);
            }
        }
    }
}
